package com.ss.plugins.sql.config;

import com.ss.plugins.sql.annotations.STable;
import com.ss.plugins.sql.core.CustomSql;
import com.ss.plugins.sql.statics.CustomSqlMap;
import com.ss.utlis.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.web.context.ServletContextAware;

import javax.servlet.ServletContext;
import java.io.File;
import java.util.*;

/**
 * 扫描标注了 @STable的类 ,在静态类中添加一个sql
 * @author xia17
 * @date 2019/7/25 14:48
 */
@Component
@EnableConfigurationProperties({SummerProperties.class})
@Slf4j
public class ApplyScanAutoConfig implements ServletContextAware {

    private SummerProperties summerProperties;
    @Autowired
    public ApplyScanAutoConfig(SummerProperties summerProperties){
        this.summerProperties = summerProperties;
    }

    private String classPath = this.getClass().getResource("/").getPath();
    private List<String> basePacks = null;
    private Set<String> classPaths = null;
    private static final String ENDS_WITH = ".class";

    @Override
    public void setServletContext(ServletContext servletContext) {
        initBasePacks();
    }

    /**
     * 初始化
     */
    private void initBasePacks(){
        //判断是否是测试运行 既@Test运行
        final String testClassName = "test-classes";
        if (classPath.contains(testClassName)){
            classPath =  classPath.substring(0, classPath.length() - testClassName.length()-1);
            classPath += "classes/";
        }
        //获取包入径
        String packages = summerProperties.getApplyPackages();
        if (packages == null || "".equals(packages)){
            log.info("未配置申请实体类所在的位置");
            return ;
        }
        basePacks = StringUtil.cutStringByChar(packages, ',');
        scanPackages();
        try {
            loaderClass();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 扫描
     */
    private void scanPackages(){
        String searchPath;
        String basePackPath;
        //扫描包下的类
        for (String basePack : basePacks) {
            log.info("开始扫描"+basePack);
            basePackPath = basePack.replace('.',File.separatorChar);
            searchPath = classPath + basePackPath;
            File file = new File(searchPath);
            if (!file.exists()){
                log.error("未找到包" + basePack);
            }
            if (!file.isDirectory()){
                log.error(basePack + "不是一个文件夹");
            }
            scanDir(file);
        }
    }

    /**
     * 扫描具体的一个包，递归扫描包下所有的文件及子包
     * @param file
     */
    private void scanDir(File file){
        if (file.isDirectory()){
            File[] files = file.listFiles();
            if (files == null){
                return;
            }
            for (File sunFile : files) {
                scanDir(sunFile);
            }
        }else {
            if (file.getName().endsWith(ENDS_WITH)){
                addClass(file.getPath());
            }
        }
    }

    /**
     * 如果是Class文件则将入径加入 classPaths Set集合中
     * @param filePath
     */
    private void addClass(String filePath){
        if (classPaths == null){
            classPaths = new HashSet<>();
            classPaths.add(filePath);
        }else {
            classPaths.add(filePath);
        }
    }

    /**
     * 读取Class文件
     * @throws ClassNotFoundException
     */
    private void loaderClass() throws ClassNotFoundException {
        if (classPaths == null){
            return;
        }
        //通过反射读取Class文件
        for (String classPath : classPaths) {
            classPath = classPath.replace(this.classPath.replace("/","\\").
                    replaceFirst("\\\\",""),"").replace("\\",".").replace(".class","");
            Class cls = Class.forName(classPath);
            addCustomSqlMap(cls);
        }
    }

    /**
     * 加入静态类中
     * @param clz
     */
    private void addCustomSqlMap(Class clz){
        if (clz.isAnnotationPresent(STable.class)){
            CustomSqlMap.put(clz.getName(),new CustomSql(clz));
        }
    }


}
